#ifndef OHOS_VIDEO_DECODER_H_
#define OHOS_VIDEO_DECODER_H_

#include <queue>
#include <mutex>
#include <condition_variable>
#include "rtc_base/logging.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/clock.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "common_video/include/video_frame_buffer_pool.h"
#include "common_video/h264/h264_bitstream_parser.h"
#include "common_video/ohos/ohos_video_buffer.h"
#include "common_video/ohos/ohos_egl_context_manager.h"
#include <native_image/native_image.h>
#include <multimedia/player_framework/native_avcodec_base.h>

namespace webrtc {

struct DecoderInputData {
  DecoderInputData(uint32_t i, OH_AVBuffer* p) {
    index = i;
    mem = p;
  }
  uint32_t index;
  OH_AVBuffer *mem;
};

struct DecoderInputVideoInfo {
    DecoderInputVideoInfo(int32_t w, int32_t h, int64_t ts, int64_t ntp_ts, uint32_t rtp_ts, VideoRotation r, absl::optional<uint8_t> q) {
        width = w;
        height = h;
        timestamp_ms = ts;
        ntp_timestamp_ms = ntp_ts;
        rtp_timestamp = rtp_ts;
        rotation = r;
        qp = q;
    }
    int32_t width;
    int32_t height;
    int64_t timestamp_ms;
    int64_t ntp_timestamp_ms;
    uint32_t rtp_timestamp;
    VideoRotation rotation;
    absl::optional<uint8_t> qp;
};

class OhosVideoDecoder : public VideoDecoder {
public:
  OhosVideoDecoder();
  virtual ~OhosVideoDecoder();
  bool Configure(const Settings& settings) override;
  int32_t Decode(const EncodedImage& inputImage, bool missingFrames, int64_t renderTimeMs = -1) override;
  int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback) override;
  int32_t Release() override;
  const char* ImplementationName() const override { return codec_name_.c_str(); }
  DecoderInfo GetDecoderInfo() const override;
  void OnCodecNeedInputData(uint32_t index, OH_AVBuffer *mem);
  void OnCodecNewOutputData(uint32_t index, OH_AVBuffer *mem);
  bool UseSurface() { return use_surface_; }
  static void OnNativeImageFrameAvailable(void *data);
  bool FrameAvailable();

private:
  bool InitGLContext();
  void DeliverByteFrame(uint32_t index, OH_AVBuffer *mem);
  void DeliverTextureFrame(uint32_t index);

public:
  int32_t oh_width_ = 0; // Maybe have padding
  int32_t oh_height_ = 0; // Maybe have padding

private:
  std::string codec_name_ = "";
  OH_AVCodec *oh_decoder_ = nullptr;
  std::condition_variable cv_;
  std::mutex queue_mutex_;
  std::queue<DecoderInputData> input_data_queue_;
  std::queue<DecoderInputVideoInfo> input_video_infos_;
  std::mutex infos_mutex_;
  bool wait_key_frame_ = true;
  DecodedImageCallback* callback_ = nullptr;
  VideoFrameBufferPool pool_;
  H264BitstreamParser h264_bitstream_parser_;
  int32_t width_ = 0;
  int32_t height_ = 0;
  bool use_surface_ = true;
  OH_NativeImage *native_image_ = nullptr;
  OHNativeWindow *native_window_ = nullptr;
  std::unique_ptr<EGLRenderContext> gl_context_;
  GLuint texture_id_ = 0;
  EGLSurface egl_surface_ = EGL_NO_SURFACE;
  OH_OnFrameAvailableListener native_image_frame_available_listener_{};
  OhosVideoBuffer::TextureBuffer texture_buffer_;
};

}  // namespace webrtc
#endif // OHOS_VIDEO_DECODER_H_
